﻿//==============================================================
//  Create by whl at 4/11/2014 10:44:14 AM.
//  Version 1.0
//  
//==============================================================


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cn.Finder.SDKFramework.Response;
using System.Reflection;
using System.Xml.Serialization;
using Jayrock.Json.Conversion;
using System.Collections;
using Cn.Finder.SDKFramework.Attri;
using Cn.Finder.SDKFramework.Util;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;

namespace Cn.Finder.SDKFramework.Parser
{
    /// <summary>
    /// Json解析器
    /// </summary>
    public  class JsonParser :IParser
    {
         // Fields
        private static readonly Dictionary<string, Dictionary<string, ApiAttribute>> attrs;

        // Methods
        static JsonParser()
        {
            attrs = new Dictionary<string, Dictionary<string, ApiAttribute>>();
        }
        public JsonParser()
        {

        }
        public object FromJson(IReader reader, Type type)
        {

            object retObj = null;
            Dictionary<string, ApiAttribute>.Enumerator enumerator = this.GetAttributes(type).GetEnumerator();
            while (enumerator.MoveNext())
            {
                KeyValuePair<string, ApiAttribute> current = enumerator.Current;
                ApiAttribute attribute = current.Value;


                string itemName = attribute.ItemName;
                string listName = attribute.ListName;
                if (reader.HasReturnField(itemName) || (!string.IsNullOrEmpty(listName) && reader.HasReturnField(listName)))
                {
                    object value = null;
                    if (attribute.ListType != null)
                    {
                        value = reader.GetListObjects(listName, itemName, attribute.ListType, new DConvert(this.FromJson));
                    }
                    else if (typeof(string) == attribute.ItemType)
                    {
                        object primitiveObject = reader.GetPrimitiveObject(itemName);
                        if (primitiveObject != null)
                        {
                            value = primitiveObject.ToString();
                        }
                    }
                    // new add
                    else if (typeof(Int32) == attribute.ItemType)
                    {
                        object primitiveObject = reader.GetPrimitiveObject(itemName);
                        if (primitiveObject != null)
                        {
                            value = ((IConvertible)primitiveObject).ToInt32(null);
                        }
                    }

                    else if (typeof(float) == attribute.ItemType || typeof(Double) == attribute.ItemType)
                    {
                        object primitiveObject = reader.GetPrimitiveObject(itemName);
                        if (primitiveObject != null)
                        {
                            value = ((IConvertible)primitiveObject).ToSingle(null);
                        }
                    }
                    else if (typeof(Double) == attribute.ItemType)
                    {
                        object primitiveObject = reader.GetPrimitiveObject(itemName);
                        if (primitiveObject != null)
                        {
                            value = ((IConvertible)primitiveObject).ToDouble(null);
                        }
                    }

                    else if (typeof(long) == attribute.ItemType)
                    {
                        object primitiveObject = reader.GetPrimitiveObject(itemName);
                        if (primitiveObject != null)
                        {
                            value = ((IConvertible)primitiveObject).ToInt64(null);
                        }
                    }
                    else if (typeof(bool) == attribute.ItemType)
                    {
                        value = reader.GetPrimitiveObject(itemName);
                    }
                    else if (typeof(DateTime) == attribute.ItemType)
                    {
                        object primitiveObject = reader.GetPrimitiveObject(itemName);
                        if (primitiveObject == null)
                        {

                        }
                        else if (primitiveObject != null && !primitiveObject.Equals(""))
                        {
                          //  DateTime dt = DateTime.ParseExact(primitiveObject.ToString(), Constants.DATE_FORMAT, System.Globalization.CultureInfo.CurrentCulture);
                            DateTime dt = Convert.ToDateTime(primitiveObject.ToString());

                            value = dt;
                        }
                    }
                    
                    else
                    {
                        value = reader.GetReferenceObject(itemName, attribute.ItemType, new DConvert(this.FromJson));
                    }
                    if (value != null)
                    {
                        if (retObj == null)
                        {
                            retObj = Activator.CreateInstance(type);
                        }
                        object[] parameters = new object[] { value };
                        attribute.Method.Invoke(retObj, parameters);
                    }
                }
            }
            return retObj;

        }


        /// <summary>
        /// 获取 类型下的属性 对应的具体属性 是单个对象 还是结合等 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private Dictionary<string, ApiAttribute> GetAttributes(Type type)
        {
            Dictionary<string, ApiAttribute> dictionary = null;
            if (!attrs.TryGetValue(type.FullName, out dictionary) || (dictionary == null))
            {
                dictionary = new Dictionary<string, ApiAttribute>();
                foreach (PropertyInfo info in type.GetProperties())
                {
                    ApiAttribute attribute = new ApiAttribute
                    {
                        Method = info.GetSetMethod()
                    };
                    XmlElementAttribute[] customAttributes = info.GetCustomAttributes(typeof(XmlElementAttribute), true) as XmlElementAttribute[];
                    if ((customAttributes != null) && (customAttributes.Length > 0))
                    {
                        attribute.ItemName = customAttributes[0].ElementName;
                    }
                    if (attribute.ItemName == null)
                    {
                        
                        JsonArrayItemAttribute[] attributeArray2 = info.GetCustomAttributes(typeof(JsonArrayItemAttribute), true) as JsonArrayItemAttribute[];
                        if ((attributeArray2 != null) && (attributeArray2.Length > 0))
                        {
                            attribute.ItemName = attributeArray2[0].ElementName;
                        }
                        Cn.Finder.SDKFramework.Attri.JsonArrayAttribute[] attributeArray3 = info.GetCustomAttributes(typeof(Cn.Finder.SDKFramework.Attri.JsonArrayAttribute), true) as Cn.Finder.SDKFramework.Attri.JsonArrayAttribute[];
                        if ((attributeArray3 != null) && (attributeArray3.Length > 0))
                        {
                            attribute.ListName = attributeArray3[0].ElementName;
                        }
                        if (attribute.ListName == null)
                        {
                            Newtonsoft.Json.JsonPropertyAttribute[] jsonPropertys = info.GetCustomAttributes(typeof(Newtonsoft.Json.JsonPropertyAttribute), false) as Newtonsoft.Json.JsonPropertyAttribute[];
                            if ((jsonPropertys != null) && (jsonPropertys.Length > 0))
                            {
                                attribute.ItemName = jsonPropertys[0].PropertyName;
                            }
                            else
                            {
                                string preStr = info.Name.Substring(0, 1).ToLower();
                                string propName = preStr;
                                if (info.Name.Length > 1)
                                {
                                    propName += info.Name.Substring(1);
                                }
                                attribute.ItemName = propName;
                            }
                           
                        }
                    }
                    if (info.PropertyType.IsGenericType)
                    {
                        Type[] genericArguments = info.PropertyType.GetGenericArguments();
                        attribute.ListType = genericArguments[0];
                    }
                    else
                    {
                        attribute.ItemType = info.PropertyType;
                    }
                    dictionary.Add(info.Name, attribute);
                }
                attrs[type.FullName] = dictionary;
            }
            return dictionary;


        }
       
        
        public T Parse<T>(string body) where T : ApiResponse
        {
            /*
            T local = null;
            IDictionary dictionary = JsonConvert.Import(body) as IDictionary;
            if (dictionary == null)
            {
                goto Label_0093;
            }
            IDictionary json = null;
            IEnumerator enumerator = dictionary.Keys.GetEnumerator();
            try
            {
                while (enumerator.MoveNext())
                {
                    object current = enumerator.Current;
                    json = dictionary[current] as IDictionary;
                    goto Label_006D;
                }
            }
            finally
            {
                IDisposable disposable = enumerator as IDisposable;
                if (disposable != null)
                {
                    disposable.Dispose();
                }
            }
        Label_006D:
            if (json != null)
            {
                IReader reader = new JsonReader(json);
                local = (T)this.FromJson(reader, typeof(T));
            }
        Label_0093:
            if (local == null)
            {
                local = Activator.CreateInstance<T>();
            }
            if (local != null)
            {
                local.Body = body;
            }
            return local;*/

            T resp = null;
            IDictionary dictionary = Jayrock.Json.Conversion.JsonConvert.Import(typeof(IDictionary),body) as IDictionary;
            if (dictionary == null)
            {
                if (resp == null)
                {
                    resp = Activator.CreateInstance<T>();
                }
                if (resp != null)
                {
                    resp.Body = body;
                }
            }
            else
            {
             
              
               // IDictionary json = null;
           //     IEnumerator enumerator = dictionary.Keys.GetEnumerator();
                /*  try
                  {  
                      while (enumerator.MoveNext())
                      {
                          object current = enumerator.Current;
                          json = dictionary[current] as IDictionary;

                          if (json != null)
                          {
                            //  IReader reader = new JsonReader(json);
                              //resp = (T)this.FromJson(reader, typeof(T));
                          }
                          else
                          {
                              if (resp == null)
                              {
                                  resp = Activator.CreateInstance<T>();
                              }
                            
                          }
                      }

                      if (resp == null)
                      {
                          resp = Activator.CreateInstance<T>();
                      }
                      else
                      {
                          resp.Body = body;
                      }
                  }
                  finally
                  {
                      IDisposable disposable = enumerator as IDisposable;
                      if (disposable != null)
                      {
                          disposable.Dispose();
                      }
                  }
                  */
                IReader reader = new JsonReader(dictionary);
                resp = (T)this.FromJson(reader, typeof(T));
                if (resp == null)
                {
                    resp = Activator.CreateInstance<T>();
                }
                else
                {
                    resp.Body = body;
                }

            }
            return resp;

        }

    }
}
